import "@ethersproject/shims";
import { ethers } from 'ethers';
import { TypedDataUtils } from "eth-sig-util";
import api from "@/request/api";
import { global } from '@/config/config'
import { getValue, setObjectValue } from "../deviceStorage";
import { AESdecrypt } from "../util";

let rpcProvider
let rpcNode = getValue('RPCNode')
if (rpcNode && rpcNode.includes('http')) {
    rpcProvider = new ethers.providers.JsonRpcProvider(rpcNode);
} else {
    rpcProvider = new ethers.providers.JsonRpcProvider(global.RPCNode);
}
const httpsProvider = rpcProvider

const getSafeDeploymentABI = (safeAccounts, numConfirmations, safeCreationSalt) => {
    //主合约的setup功能.
    const masterABI = ["function setup(address[] calldata _owners, uint256 _threshold, address to, bytes calldata data, address fallbackHandler, address paymentToken, uint256 payment, address payable paymentReceiver)"]
    const masterIface = new ethers.utils.Interface(masterABI);
    const masterAbi = masterIface.encodeFunctionData("setup", [safeAccounts, numConfirmations, global.ZERO_ADDRESS, global.EMPTY_DATA, global.fallbackHandler, global.ZERO_ADDRESS, 0, global.ZERO_ADDRESS]);
    //工厂合约的createProxyWithNonce功能.
    const fatoryABI = ["function createProxyWithNonce(address _singleton, bytes memory initializer,uint256 saltNonce)"]
    const fatoryABIIface = new ethers.utils.Interface(fatoryABI);
    const fatoryAbi = fatoryABIIface.encodeFunctionData("createProxyWithNonce", [global.masterCopyAddress, masterAbi, safeCreationSalt]);
    return fatoryAbi;
}

const estimateGasForDeployingSafe = async (safeAccounts, numConfirmations, safeCreationSalt) => {
    const data_ = getSafeDeploymentABI(safeAccounts, numConfirmations, safeCreationSalt);
    const estimateGas = await httpsProvider.estimateGas({
        to: global.fatoryAddress,
        data: data_
    })
    return estimateGas;
}

export const getTransactionReceipt = async (hash) => {
    return await httpsProvider.getTransactionReceipt(hash)
}

export const getTotalFee = (maxFeePerGas, gasLimit) => {
    return ethers.utils.formatUnits(maxFeePerGas * gasLimit, 'ether')
}

export const getFeeData = async (address, safeAccounts, numConfirmations) => {
    const safeCreationSalt = Date.parse(new Date());
    const nonce = await httpsProvider.getTransactionCount(address);
    const feeData = await httpsProvider.getFeeData();
    const gasConsume = await estimateGasForDeployingSafe(safeAccounts, numConfirmations, safeCreationSalt);
    const totalFee = ethers.utils.formatUnits(feeData["maxFeePerGas"] * gasConsume, 'ether')
    let result = {
        nonce,
        feeData,
        gasConsume,
        totalFee
    }
    return result
}

//safeAccounts：多签钱包持有者, 数组形式.
//numConfirmations：执行交易所需签名的阈值.
//privateKey：创建多签钱包的地址私钥.
export const createWallet = async (safeAccounts, numConfirmations, mnemonicStr, customFeeData) => {
    let selectedWallet = getValue('selectedWallet')
    const safeCreationSalt = Date.parse(new Date());
    const wallet = ethers.Wallet.fromMnemonic(mnemonicStr, selectedWallet.wallet_name)
    const address = wallet.address
    const deploymentInputData = getSafeDeploymentABI(safeAccounts, numConfirmations, safeCreationSalt);
    const nonce = customFeeData && customFeeData.nonce ? customFeeData.nonce : await httpsProvider.getTransactionCount(address);
    //用于获取支持EIP-1559 类型2 交易的 maxFeePerGas和maxPriorityFeePerGas值.
    const feeData = customFeeData && customFeeData.feeData ? customFeeData.feeData : await httpsProvider.getFeeData();
    const gasConsume = customFeeData && customFeeData.gasConsume ? customFeeData.gasConsume : await estimateGasForDeployingSafe(safeAccounts, numConfirmations, safeCreationSalt);
    const tx = {
        type: 2,
        nonce: nonce,
        to: global.fatoryAddress,
        maxPriorityFeePerGas: feeData["maxPriorityFeePerGas"], // Recommended maxPriorityFeePerGas
        maxFeePerGas: feeData["maxFeePerGas"], // Recommended maxFeePerGas
        value: "0x0",  // Send eth number
        gasLimit: gasConsume, // Basic transaction costs exactly 21000
        data: deploymentInputData, //Input data.
        chainId: 5, // Ethereum network id, this is goerli id
    };
    //签署交易.
    const signedTx = await wallet.signTransaction(tx);
    const txHash = ethers.utils.keccak256(signedTx);
    //发送交易.
    await httpsProvider.sendTransaction(signedTx)
    return txHash
};

const getSafeNonceABI = () => {
    const masterABI = ["function nonce()"]
    const masterIface = new ethers.utils.Interface(masterABI);
    const masterAbi = masterIface.encodeFunctionData("nonce", []);
    return masterAbi;
}

export const getSafeNonce = async (address) => {
    const inputData = getSafeNonceABI();
    const message = await httpsProvider.call({
        to: address,
        data: inputData
    })
    return ('0x' + Number(message).toString(16));
}

const getSafeChainId = async () => {
    let re = await httpsProvider.getSigner().getChainId()
    return re
}

const getSafeChainDetail = async (chainId) => {
    let re = await api.get_chain_detail(chainId)
    return re
}

export const getSafeChainInfo = async () => {
    let chainId = await getSafeChainId()
    let chainDetail = await getSafeChainDetail(chainId)
    setObjectValue('chainId', chainId)
    setObjectValue('chainDetail', chainDetail)
}

export const getRPCNodeInfo = async () => {
    let rpcNode = await api.axios_get(`${global.BaseURL}wallet/eth_single/get_node`)
    setObjectValue('RPCNode', rpcNode.node_url)
}

export const getSignatureFromSafeTxHash = (safeTxHash, selectedWallet) => {
    let pwd = getValue('lockPwd')
    let encryptStr = getValue('mnemonicStr')
    let decryptStr = AESdecrypt(pwd.substring(0, 16), pwd.substring(16), encryptStr)
    const wallet = ethers.Wallet.fromMnemonic(decryptStr, selectedWallet.wallet_name)
    const flatSig = wallet._signingKey().signDigest(ethers.utils.arrayify(safeTxHash))
    const v = ethers.utils.hexValue(flatSig.v)
    //无法直接使用flatSig中生成的签名, 会对其进行编码, 需要手动使用r,s,v来重构签名.
    const sig = flatSig.r + flatSig.s.slice(2) + v.slice(2);
    return sig
}

export const generateTypedDataFrom = (safeAddress, nonce, safeTxGas, to, valueInWei) => {
    let chainId = getValue('chainId')
    const typedData = {
        types: {
            EIP712Domain: global.EIP712_DOMAIN,
            SafeTx: global.SAFETX
        },
        domain: {
            chainId: chainId,
            verifyingContract: safeAddress,
        },
        primaryType: 'SafeTx',
        message: {
            to,
            value: valueInWei,
            data: global.EMPTY_DATA,
            operation: 0,
            safeTxGas,
            baseGas: "0",
            gasPrice: "0",
            gasToken: global.ZERO_ADDRESS,
            refundReceiver: global.ZERO_ADDRESS,
            nonce,
        },
    }
    return typedData
}

const getSafeTxHashAndSigs = (safeAddress, nonceData, toAddress, amount, selectedWallet) => {
    const typedData = generateTypedDataFrom(safeAddress, nonceData.currentNonce, nonceData.safeTxGas, toAddress, amount)
    const safeTxHash = `0x${TypedDataUtils.sign(typedData).toString('hex')}`
    const signature = getSignatureFromSafeTxHash(safeTxHash, selectedWallet)
    return { safeTxHash, signature }
}

export const getETHSignData = async (selectedSafeWallet, sendData) => {
    //地址标准格式化
    let safeAddress = ethers.utils.getAddress(selectedSafeWallet.address)
    let toAddress = ethers.utils.getAddress(sendData.address)
    let obj = getValue('selectedWallet')
    let senderAddress = ethers.utils.getAddress(obj.address)
    let amount = sendData.amount
    //查询安全钱包的nonce值
    let payload1 = JSON.stringify({
        "to": toAddress,
        "value": amount,
        "data": global.EMPTY_DATA,
        "operation": 0
    })
    let nonceData = sendData.nonceData ? sendData.nonceData : await api.get_safe_nonce(safeAddress, payload1)
    if (nonceData) {
        const { safeTxHash, signature } = getSafeTxHashAndSigs(safeAddress, nonceData, toAddress, amount, obj)
        console.log("safeTxHash", safeTxHash)
        console.log("signature", signature)
        let payload2 = {
            to: toAddress,
            value: amount,
            data: global.EMPTY_DATA,
            operation: 0,
            nonce: nonceData.currentNonce?.toString(),
            safeTxGas: nonceData.safeTxGas,
            baseGas: "0",
            gasPrice: "0",
            gasToken: global.ZERO_ADDRESS,
            refundReceiver: global.ZERO_ADDRESS,
            safeTxHash,
            sender: senderAddress,
            origin: null,
            signature
        }
        let res = await api.submit_safe_transactions(safeAddress, payload2)
        return res
    } else {
        return null
    }
}

export const getETHRejectData = async (selectedSafeWallet, nonce) => {
    //地址标准格式化
    let safeAddress = ethers.utils.getAddress(selectedSafeWallet.address)
    let obj = getValue('selectedWallet')
    let senderAddress = ethers.utils.getAddress(obj.address)
    let nonceData = {
        currentNonce: nonce,
        safeTxGas: 0,
    }
    let amount = '0'
    const { safeTxHash, signature } = getSafeTxHashAndSigs(safeAddress, nonceData, safeAddress, amount, obj)
    console.log("safeTxHash", safeTxHash)
    console.log("signature", signature)
    let payload2 = {
        to: safeAddress,
        value: amount,
        data: global.EMPTY_DATA,
        operation: 0,
        nonce: nonceData.currentNonce?.toString(),
        safeTxGas: nonceData.safeTxGas,
        baseGas: "0",
        gasPrice: "0",
        gasToken: global.ZERO_ADDRESS,
        refundReceiver: global.ZERO_ADDRESS,
        safeTxHash,
        sender: senderAddress,
        origin: null,
        signature
    }
    let res = await api.submit_safe_transactions(safeAddress, payload2)
    return res
}